Repository navigation
Keep keyboard focus off hidden browser tabs - #4310
Merged
Merged
Conversation
A hidden desktop Browser tab takes native keyboard focus whenever its page navigates on its own (a reload timer, meta refresh, or live reload), so typing in any other thread loses the composer. get-bb#4303 returns that focus to the host for automation-controlled tabs; apply the same guard to hidden tabs. Fixes get-bb#4308 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ymichael
added a commit
that referenced
this pull request
Nov 3, 2026
…6917) ## Human comments ## What was wrong When a page navigates on its own, Electron gives its `WebContentsView` native keyboard focus. #4310 returned that focus to the host only for hidden or agent-controlled tabs. A visible Browser tab showing a self-refreshing page, such as the connect-next "Nothing answered at this address" page (meta refresh every 10 s, `apps/connect-next/src/pages.ts`), still pulled the cursor out of the composer on every reload. ## What changed `apps/desktop/src/desktop-browser-view.ts`: - On `did-start-loading`, a tab that does not have focus is marked as waiting for a pointer press (`pointerFocusListener`, an `input-event` listener). - `rejectsNativeFocus` now also covers marked tabs. Focus a marked tab gains is returned to the host one tick later, through the same path as hidden tabs. - The mark clears on a pointer press inside the page (`mouseDown`, `pointerDown`, `touchStart`, `gestureTapDown`) or when bb focuses the tab explicitly (`focusEntryWithoutNotifying`). Explicit focus covers address bar submit, Take over and the pane focus shortcuts. Mouse moves and scrolls do not clear it. - The focus decision waits one tick, so a click counts whether Electron delivers `focus` before or after the `mouseDown`. The `focused` push is sent only if the tab still has focus at that point. There are no wire, CLI or docs changes. ## How you verified - New tests in `apps/desktop/test/desktop-browser-view-manager.test.ts`: - A reloading visible tab returns focus to the host on repeated loads. - A reloaded tab keeps focus after a press that lands before the focus, a press that follows it, or an explicit focus. - `pnpm exec turbo run test --filter=@bb/desktop -- test/desktop-browser-view-manager.test.ts`: 114 passed. - `pnpm exec turbo run typecheck --filter=@bb/desktop`: clean. - Manual check in a packaged `pnpm desktop:worktree` build against a local page that reloads every 3 s is in progress. Still to confirm: the composer keeps focus across reloads; clicking into the page keeps focus; address bar, Take over and pane shortcuts still focus the page. > AGENT GENERATED 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Human comments
What was wrong
Electron gives a
WebContentsViewnative keyboard focus when its page navigates, even while the view is hidden withsetVisible(false). A persisted desktop Browser tab whose page reloads on its own (a retry timer, a meta refresh, live reload) therefore took focus from the BB window every time it navigated. The operator lost the composer in every other thread, and on the New thread page. The view manager forwarded that focus to the renderer as a normal browser focus. #4303 added a guard that returns focus to the host, but only for automation-controlled tabs. See #4308 for the investigation, the live trace and a standalone Electron repro.What changed
apps/desktop/src/desktop-browser-view.ts:!entry.visible) now takes the same path as an automation-controlled one: its native focus is not reported, andreturnFocusToHostgives focus back to the host on the next tick.controlledViewHasFocustreats hidden entries the same way, so that return actually runs.focusEntryWithoutNotifying, Take over), which still setssuppressNextFocusNotificationfirst.apps/desktop/test/desktop-browser-view-manager.test.ts: one regression test. A hidden tab's native focus returns to the host and does not pushbb-desktop:browser:focused.HOST_DAEMON_PROTOCOL_VERSION, CLI, SDK or documentation changes.How you verified
main(focusHostWebContentsis never called) and passes with the fix.pnpm exec turbo run test --filter=@bb/desktop --force: 47 files, 448 tests passed, 1 skipped. One earlier run hit a transient failure inelectron-builder-config.test.ts, which is unrelated to this change. That file passes on its own both with and without this change, and on the rerun.pnpm exec turbo run typecheck lint --filter=@bb/desktoppassed.oxfmt --checkpasses on the changed source file. The only formatter findings in the test file are in pre-existing code outside this diff, and I left them untouched.createDesktopBrowserViewManager, using the repro script in Hidden desktop Browser tab steals keyboard focus whenever its page navigates on its own #4308. The script attaches a tab, hides it, focuses the host, and lets the page reload itself.mainat6f9d6f44dreproduced in 3 of 3 runs. Each reload blurred the host, pushedbb-desktop:browser:focused, and lefthost.isFocused=falsewhilewin.isFocused=true.host.isFocused=true/document.hasFocus=trueat every poll.Fixes #4308